<?php

class RegistroController extends Zend_Controller_Action{

    public function init(){
        //X\Permiso::paraController();
        $this->em = Zend_Registry::getInstance()->entitymanager;
    }

    public function indexAction(){
        //action body
    }

    public function generarAction(){
        /*X\Permiso::paraAction('Generar.Registro');*/

        $desde = $this->em->createQueryBuilder()
                        ->select('c.valor')
                        ->where("c.nombre='fin_registro'")
                        ->from('Default_Model_Configuracion', 'c')
                        ->getQuery()
                        ->execute();


        $this->view->desde = $desde[0]['valor'];
    }

    /**
     * Trae los cursos válidos para el rango de fecha especificado.
     * @param mixed $desde fecha inicial de verificación
     * @param mixed $hasta fecha final de verificación
     * @return array $cursos.
     */
    private function getCursosActivosFecha($desde, $hasta, $add_cond = array()){
        $qb = $this->em->createQueryBuilder();
        $cursos = $qb->select  ('m.idMateria')
            ->addSelect  ('c.seccion')
            ->addSelect  ('c.validoDesde')
            ->addSelect  ('c.validoHasta')
            ->addSelect  ('r.idResponsable')
            ->addSelect  ('p.idProfesor')
            ->addSelect  ('p.codigo')
            ->addSelect  ('d.dia')
            ->addSelect  ('d.horaInicio')
            ->addSelect  ('d.horaFin')
            ->addSelect  ('d.duracionHoras')
            ->addSelect  ('ca.idCarrera')
            ->addSelect  ('ca.duracionHora')
            ->from       ('Default_Model_Curso', 'c')
            ->join       ('c.carreraMateria', 'cm')
            ->join       ('c.responsables', 'r')
            ->join       ('c.detalles', 'd')
            ->join       ('r.profesor', 'p')
            ->join       ('cm.materia', 'm')
            ->join       ('cm.carrera', 'ca')
            ->where      ("c.validoDesde<='".$desde."' AND c.validoHasta>='".$desde."' OR
                                    c.validoDesde<='".$hasta."' AND c.validoHasta>='".$hasta."'");

        if(count($add_cond) > 0){
            foreach($add_cond as $cond)
                $cursos = $cursos->andWhere($cond);

        }

        $cursos = $cursos
            ->orderBy    ('p.codigo', 'asc')
            ->addOrderBy ('m.idMateria', 'asc')
            ->addOrderBy ('c.validoDesde', 'asc')
            ->addOrderBy ('d.dia', 'asc')
            ->addOrderBy ('d.horaInicio', 'asc')
            ->addOrderBy ('c.seccion', 'asc')
            ->addOrderBy ('ca.idCarrera', 'asc')
        //->addOrderBy ('c.seccion', 'asc')
            ->getQuery   ()
            ->execute    ();

        return $cursos;
    }

    /**
     * Verifica si los cursos especificados son diferentes o no de acuerdo a los criterios: profesor, materia, seccion, fecha inicial y
     * final, dia, hora inicio, hora fin.
     * @param array $curso1 los datos del primer curso
     * @param array $curso2 recordset de la base de datos para el segundo curso.
     * @return boolean true si son iguales, false en caso contrario.
     */
    private function sonCursosDiferentes($curso1, $curso2){
        return  $curso1['profesor'] != $curso2['idProfesor'] ||             // diferenciacion por profesor
                $curso1['materia']!= $curso2['idMateria'] ||                // diferenciacion por materia
                $curso1['seccion'] != $curso2['seccion'] ||                 // diferenciacion por seccion
                $curso1['desde']!=$curso2['validoDesde']->format('Y-m-d') ||// diferenciacion por fecha inicial de validez
                $curso1['hasta']!=$curso2['validoHasta']->format('Y-m-d') ||// diferenciacion por fecha final de validez
                $curso1['dia']!=$curso2['dia'] ||                           // diferenciacion por dia de la semana
                $curso1['inicio']!=$curso2['horaInicio']->format('H:i') ||  // diferenciacion por hora de inicio de la clase
                $curso1['fin']!=$curso2['horaFin']->format('H:i');          // diferenciacion por hora de fin de la clase
    }

    /**
     * Genera un array con los cursos, agrupados por: profesor, materia, seccion, fecha inicial y
     * final, dia, hora inicio, hora fin. Orden: codigo profesor, materia, fecha inicio de validez,
     * día de la semana, hora de inicio, sección, carrera.
     * @param array $desde fecha inicial de validez del curso.
     * @param array $hasta fecha en que termina la validez del curso.
     * @return array $cursosData con los cursos y sus detalles.
     */
    private function getCursosAgrupados($desde, $hasta, $add_cond = array()){
        $cursos = $this->getCursosActivosFecha($desde, $hasta, $add_cond); // todos los cursos válidos desde la base de datos
        $cursosData = array();

        $cursoData = array ();  // curso actual

        //$profActual=-1;
        //$matActual=$cursos[0]['idMateria'];
        $firstRun=true;

        /*  agrupamos los cursos por: profesor, materia, seccion, fecha inicial de validez, fecha final de validez,
            dia de la semana, hora de inicio, hora de fin   */
        foreach($cursos as $c){
            //ignore algorithm the first time
            if($firstRun){
                $cursoData = array ('materia'       => $c['idMateria'],
                    'profesor'      => $c['idProfesor'],
                    'codigo'        => $c['codigo'],
                    'responsable'   => $c['idResponsable'],
                    'carreras'      => array($c['idCarrera']),
                    'duracionHora'  => $c['duracionHora'],
                    'seccion'       => $c['seccion'],
                    'desde'         => $c['validoDesde']->format('Y-m-d'),
                    'hasta'         => $c['validoHasta']->format('Y-m-d'),
                    'dia'           => $c['dia'],
                    'inicio'        => $c['horaInicio']->format('H:i'),
                    'fin'           => $c['horaFin']->format('H:i'),
                    'duracionHoras' => $c['duracionHoras']);
                $firstRun = false;
                continue;
            }

            if($this->sonCursosDiferentes($cursoData, $c))
            {
                array_push($cursosData, $cursoData);
                unset($cursoData);

                $cursoData = array ('materia'       => $c['idMateria'],
                    'profesor'      => $c['idProfesor'],
                    'codigo'        => $c['codigo'],
                    'responsable'   => $c['idResponsable'],
                    'carreras'      => array($c['idCarrera']),
                    'duracionHora'  => $c['duracionHora'],
                    'seccion'       => $c['seccion'],
                    'desde'         => $c['validoDesde']->format('Y-m-d'),
                    'hasta'         => $c['validoHasta']->format('Y-m-d'),
                    'dia'           => $c['dia'],
                    'inicio'        => $c['horaInicio']->format('H:i'),
                    'fin'           => $c['horaFin']->format('H:i'),
                    'duracionHoras' => $c['duracionHoras']);
                continue;
            }elseif(!(in_array($c['idCarrera'],$cursoData['carreras']))){
                array_push($cursoData['carreras'],$c['idCarrera']);
            }
        }
        array_push($cursosData, $cursoData);

        return $cursosData;
    }

    /**
     * Obtiene los registros de marcaciones realizados en el rango de fechas especificados.
     * @param mixed $desde fecha de inicio de verificación.
     * @param mixed $hasta fecha de fin de verificación.
     * @return array $marcaciones.
     */
    private function getMarcacionesFecha($desde, $hasta, $add_cond = array()){
        $qb = $this->em->createQueryBuilder();

        $marcaciones = $qb ->select('h.fecha')
                            ->addSelect('h.tipo')
                            ->addSelect('h.entrada_salida')
                            ->addSelect('h.id_empleado')
                            ->from('Default_Model_HorarioDia', 'h')
                            ->where($qb->expr()->between('h.fecha', "'" . $desde . "'", "'" . $hasta . "'"));

        if(count($add_cond) > 0){
            foreach($add_cond as $cond)
                $marcaciones = $marcaciones->andWhere($cond);

        }

        $marcaciones = $marcaciones
                        //->where("h.fecha = '01-10-2012'")
                            ->orderBy('h.fecha', 'asc')
                            ->addOrderBy('h.id_empleado', 'asc')
                            ->addOrderBy('h.entrada_salida', 'asc')
                            ->getQuery()
                            ->execute();
        return $marcaciones;
    }

    /**
     * Obtiene y verifica los registros de marcaciones, dejando solo las válidas: Se consideran solo las marcaciones con entrada y salida
     * para cada profesor. Orden: fecha, empleado, hora de marcacion.
     * @param mixed $desde fecha de inicio de verificación.
     * @param mixed $hasta fecha de fin de verificación.
     * @return array $dataSet con las marcaciones consideradas válidas.
     */
    private function getMarcacionesValidasFecha($desde, $hasta, $add_cond = array()){
        //Trear marcaciones dentro del rango desde hasta, ordenados por: fecha, empleado, hora de marcacion
        $marcaciones = $this->getMarcacionesFecha($desde, $hasta, $add_cond);

        // fechas: se inicia en la fecha $desde
        list($date, $month, $year) = explode("/", $desde);
        $fechaAux = $year."-".$month."-".$date;
        $fechaActual = date('Y-m-d', strtotime($fechaAux) - 86400);

        // si el registro de marcación que se está actualizando tiene entrada y salida
        $marcaEntrada = false;
        $marcaSalida = false;

        // arrays para las marcaciones
        $data = array ('fecha' => '','dia' => '','entrada' => '','salida' => '','codigo' => '' );   // un registro de marcación
        $dataSet = array(); // todas las marcaciones válidas

        $profActual = "";

        //Considerar solo marcaciones correctas
        foreach ($marcaciones as $marca){
            // registro de marcaciones completo
            if($marcaEntrada && $marcaSalida){
                array_push($dataSet, $data);
                $marcaEntrada=false;
                $marcaSalida=false;
            }

            // siguiente profesor
            if(strcmp($marca['id_empleado'], $profActual)!=0){
                $marcaEntrada=false;
                $marcaSalida=false;
                $profActual=$marca['id_empleado'];
            }

            // marcacion en un mismo dia, luego de marcar salida
            if($marca['fecha'] == $fechaActual){
                // el registro de marcación anterior se ha completado
                if($marcaSalida){
                    //Si es salida, se actualiza la hora de salida: la última es la que vale
                    if($marca['tipo']=='SALIDA'){
                        $data['salida']=$marca['entrada_salida']->format('H:i:s');

                    //Si es entrada, es una nueva marcación
                    }else{
                        array_push($dataSet, $data);    // carga la anterior
                        $marcaSalida=false;
                        unset($data);

                        // datos de la marcación
                        $data = array ('fecha' => '','dia' => '','entrada' => '','salida' => '');
                        $data['fecha'] = $fechaActual->format('Y-m-d');
                        $data['dia'] = date('N', strtotime($data['fecha']));
                        $data['entrada']=$marca['entrada_salida']->format('H:i:s');
                        $data['codigo']=substr($marca['id_empleado'],1,4);
                        $marcaEntrada = true;
                    }
                }

                // entrada en la fecha actual
                elseif($marca['tipo']=='ENTRADA' && !$marcaEntrada){
                    $marcaSalida=false;
                    unset($data);

                    // datos de marcación
                    $data = array ('fecha' => '','dia' => '','entrada' => '','salida' => '');
                    $data['fecha'] = $fechaActual->format('Y-m-d');
                    $data['dia'] = date('N', strtotime($data['fecha']));
                    $data['entrada']=$marca['entrada_salida']->format('H:i:s');
                    $data['codigo']=substr($marca['id_empleado'],1,4);
                    $marcaEntrada = true;
                }

            }

            // nuevo dia
            if($marca['fecha']!=$fechaActual){
                //La salida del dia anterior fue la ultima, se agrega la marcacion
                if($marcaEntrada && $marcaSalida){
                    array_push($dataSet, $data);
                    $marcaSalida=false;
                }

                // se inicia un nuevo registro de marcación
                $marcaEntrada=false;
                $fechaActual=$marca['fecha'];   // la nueva fecha actual es la leída en el registro actual de marcaciones (desde la base de datos).

                // si tenemos un registro de entrada, se inicia un nuevo registro de marcaciones. Si no hay marcación de entrada, se ignora la marcación.
                if($marca['tipo']=='ENTRADA'){
                    unset($data);
                    $data = array ('fecha' => '','dia' => '','entrada' => '','salida' => '');
                    $data['fecha'] = $fechaActual->format('Y-m-d');
                    $data['dia'] = date('N', strtotime($data['fecha']));
                    $data['entrada']=$marca['entrada_salida']->format('H:i:s');
                    $data['codigo']=substr($marca['id_empleado'],1,4);
                    $marcaEntrada = true;
                }
            }

            //Marcacion de salida, puede no ser la última, si no hay marca de entrada en ese día, la marcación es ignorada
            if($marca['fecha']==$fechaActual && $marca['tipo']=='SALIDA' && $marcaEntrada){
                $data['salida']=$marca['entrada_salida']->format('H:i:s');
                $marcaSalida = true;
            }
        }
        //Se agrega la ultima marcacion correcta
        if($marcaEntrada && $marcaSalida){
            array_push($dataSet, $data);
        }

        return $dataSet;
    }

    /**
     * Obtiene los elementos del calendario que representan suspensiones de clase, dentro del rango
     * de fechas especificado.
     * @param mixed $desde fecha de inicio
     * @param mixed $hasta fecha fin
     * @return array $registerSet nuevos registros de asistencia
     */
    private function getSuspensionesClases($desde, $hasta){
        $qb=$this->em->createQueryBuilder();


        //Si se llegara a modificar el calendario para cargar otras cosas ademas
        //de feriados/suspensiones/asuetos, se debera verificar el tipo y solo tener
        //en cuenta los que impliquen la suspension de clases. ->addWhere(tipo!=1)
        //Sea 1 el unico tipo que no implique suspension de clase/feriado, etc

        //Se traen los detalles del calendario del corriente año
        $detallesCalendario = $qb->select   ('dc.fechaInicio')
            ->addSelect ('dc.fechaFin')
            ->addSelect ('dc.horaInicio')
            ->addSelect ('dc.horaFin')
            ->addSelect ('dc.semestres')
            ->addSelect ('dc.carrera')
            ->from      ('Default_Model_Calendario', 'dc')
            ->where     ($qb->expr()->between('dc.fechaInicio', "'".$desde."'", "'".$hasta."'"))
            ->orderBy   ('dc.fechaInicio', 'asc')
            ->getQuery ()
            ->execute  ();

        return $detallesCalendario;
    }

    /**
     * Vuelve a generar los registros de asistencia de acuerdo a las clases válidas solamente.
     * @param mixed $desde fecha inicial
     * @param mixed $hasta hasta que fecha verificar
     * @param array $registerSet registros a verificar
     * @return array $registerSet nuevos registros de asistencia
     */
    private function filtrarClasesValidas($desde, $hasta, $registerSet, $cursosData){
        $detallesCalendario = $this->getSuspensionesClases($desde, $hasta);

        //Solo si existen eventos de suspension de clases
        if(count($detallesCalendario)>0){

            $event = array ('fecha'  => '', 'inicio' => '', 'fin'    => '', 'semestres'  => '', 'carrera' => '');
            $eventSet = array();

            foreach ($detallesCalendario as $d) {
                //definir semestre afectados por evento
                $sems = array();
                $aux = $d['semestres'];
                $candidate = "";
                $length = strlen($aux);
                $isRange= false;
                $from="";
                $to="";

                /* se obtiene la lista de semestres en los que es válida la suspensión actualmente analizada */
                for($i = 0; $i < $length; $i++) {
                    // semestre válido
                    if(ctype_digit($aux[$i])){
                        $candidate.=$aux[$i];
                    }
                    // rango de semestres: semestre inicial en $candidate
                    if($aux[$i]=='-'){
                        $isRange=true;
                        $from=intval($candidate);
                        unset($candidate);
                    }
                    // finaliza el patrón de semestres actual: patrones separados entre comas
                    if($aux[$i]==','||$i+1==$length){
                        if($isRange){
                            // ultimo semestre del rango
                            $to=intval($candidate);
                            for($j=$from;$j<=$to;$j++){
                                array_push($sems, $j);
                            }
                            unset($from);
                            unset($to);
                            $isRange=false;
                        }else{
                            array_push($sems, intval($candidate));
                        }
                        unset($candidate);
                    }
                }

                // cada día de suspensión en un array de eventos
                //Transformar rango de fechas en dias y cargar demas datos de eventos
                if($d['fechaInicio']->format('d/m/Y') != $d['fechaFin']->format('d/m/Y')){
                    $inicio = $d['fechaInicio']->format('Y-m-d');
                    $hasta  = $d['fechaFin']->format('Y-m-d');
                    while($inicio <= $hasta){
                        $event = array ('fecha'     => $inicio,
                            'inicio'    => $d['horaInicio']->format('H:i'),
                            'fin'       => $d['horaFin']->format('H:i'),
                            'semestres' => $sems,
                            'carrera'   => $d['carrera']);
                        array_push($eventSet, $event);
                        unset($event);
                        $inicio = date ("Y-m-d", strtotime("+1 day", strtotime($inicio)));
                    }

                } else {
                    $event = array ('fecha'     => $d['fechaInicio']->format('d/m/Y'),
                        'inicio'    => $d['horaInicio']->format('H:i'),
                        'fin'       => $d['horaFin']->format('H:i'),
                        'semestres' => $sems,
                        'carrera'   => $d['carrera']);
                    array_push($eventSet, $event);
                    unset($event);
                }
            }

            //Falta considerar eventos que no pertenecen a todas las carreras, por ejemplo
            // un congreso de arquitectura hace que se suspendan las clases solo en arquitectura

            //Cargar registros de clases en dias feriados/asuetos/suspensiones
            foreach($eventSet as $e){
                foreach($cursosData as $curso){
                    $fechaEvento = $e['fecha'];
                    list($date, $month, $year) = explode("/", $fechaEvento);
                    $fechaEvento = $year."-".$month."-".$date;
                    //list($date, $month, $year) = explode("/", $curso['validoDesde']);
                    //$vDesde = $year."-".$month."-".$date;
                    //list($date, $month, $year) = explode("/", $curso['validoHasta']);
                    //$vHasta = $year."-".$month."-".$date;
                    if($e['carrera']==0 || in_array($e['carrera'], $curso['carreras'])){
                        if($fechaEvento >= $curso['desde'] && $fechaEvento <= $curso['hasta']){
                            //if($fechaEvento >= $vDesde && $fechaEvento <= $vHasta){
                            //echo "Evento: ".$fechaEvento." Desde: ".$vDesde." Hasta: ".$vHasta."\n";
                            /*list($date, $month, $year) = explode("/", $fechaEvento);
                            $fechaEvento = $year."-".$month."-".$date;*/
                            $dia = date ('N', strtotime($fechaEvento));
                            if($dia == $curso['dia']){
                                if($curso['inicio'] >= $e['inicio'] && $curso['inicio'] <= $e['fin']){

                                    $reg = array ('fecha'  => $e['fecha'],
                                        'inicio' => $curso['inicio'],
                                        'fin'    => $curso['fin'],
                                        'horas'  => $curso['duracionHoras'],
                                        'horacatedra'  => $curso['duracionHora'],
                                        'horasrequeridas' =>$curso['duracionHoras'],
                                        'estado' => 'N',
                                        'materia'  => $curso['materia'],
                                        'resp'   => $curso['responsable'],
                                        'seccion'=> $curso['seccion'] );

                                    array_push($registerSet, $reg);
                                    unset($reg);

                                }
                            }
                        }
                    }
                }
            }
            //return;
        }

        return $registerSet;
    }

    private static function overlapping($start1,$end1,$start2,$end2){
        // los rangos de hora a verificar deberán tener una duración > 0
        if($start1 != $end1 && $start2 != $end2){
            if(($start1>$start2&&$start1<$end2)||($start2>$start1&&$start2<$end1)||
                ($end1>$start2&&$end1<$end2)||($end2>$start1&&$end2<$end1)||
                ($start1==$start2&&$end1==$end2)){
                return true;
            }
        }

        return false;
    }

    private function findConflictos($registerSet){
        // compara un registro con todos los demás
        foreach($registerSet as &$r1){
            foreach($registerSet as &$r2){
               //if((strcmp($r1['estado'],'N')==0)||(strcmp($r2['estado'],'N')==0)){
                    if($r1!=$r2){
                        // la misma fecha
                        if($r1['fecha']==$r2['fecha']){
                            // se superponen las horas
                            if(RegistroController::overlapping($r1['inicio'], $r1['fin'], $r2['inicio'], $r2['fin'])){
                                //Clases distintas en simultaneo para un mismo profesor, conflicto de materia
                                if($r1['resp']==$r2['resp']){
                                    if(strcmp($r1['estado'],'N')==0){
                                        $r1['estado']='C';
                                    }
                                    if(strcmp($r2['estado'],'N')==0){
                                        $r2['estado']='C';
                                    }
                                    if(strcmp($r1['estado'],'P')==0){
                                        $r1['estado']='A';
                                    }
                                    if(strcmp($r2['estado'],'P')==0){
                                        $r2['estado']='A';
                                    }
                                }
                                //Misma clase dada en compañia de otro profesor, conflicto responsable
                                elseif($r1['materia']==$r2['materia'] && $r1['seccion']==$r2['seccion']){
                                    if(strcmp($r1['estado'],'N')==0){
                                        $r1['estado']='P';
                                    }
                                    if(strcmp($r2['estado'],'N')==0){
                                        $r2['estado']='P';
                                    }
                                    if(strcmp($r1['estado'],'C')==0){
                                        $r1['estado']='A';
                                    }
                                    if(strcmp($r2['estado'],'C')==0){
                                        $r2['estado']='A';
                                    }
                                }
                            }
                        }
                    }
               //}
            }
        }

        return $registerSet;
    }


    public function ajaxGenerarAction(){
        $desde = $this->_request->getPost('desde');                             // desde la fecha que esta guardada en las configuraciones
        $hasta = date("d/m/Y", mktime(0,0,0,date("m"),date("d")-1,date("Y")));  // hasta ayer

        // traer los cursos diferenciados de la siguiente forma: profesor, materia, seccion, fecha inicial de validez, fecha final de validez,
        // dia de la semana, hora de inicio, hora de fin. Orden de los registros: fecha, empleado, hora de marcacion.
        // Orden: profesor, materia, fecha inicio de validez, día de la semana, hora de inicio, sección, carrera.
        $cursosData = $this->getCursosAgrupados($desde, $hasta);

        // traer las marcaciones válidas dentro del rango de fechas establecido.
        // Orden: fecha, empleado, hora de marcacion.
        $dataSet = $this->getMarcacionesValidasFecha($desde, $hasta);

        $handle = fopen("hola.html","w+");
        fwrite($handle,'cursos <br>');
        foreach($cursosData as $datos){
            foreach($datos as $dato=>$valor)
                fwrite($handle, $dato.'='.$valor);
            fwrite($handle, '<br>');
        }
        fwrite($handle,'marcaciones <br>');
        foreach($dataSet as $marcacion){
            foreach($marcacion as $dato=>$valor){
                fwrite($handle, $dato.'='.$valor);
            }
            fwrite($handle, '<br>');
        }

        //Se cargaran los registros en arreglos auxiliares, para luego compararlos
        //y verificar los conflictos, de esta manera seran cargados a la base de datos con su
        //estado correspondiente
        $registerSet = array(); //array con todos los registros de datos del curso para cada marcación realizada. Datos: fecha de marcación, inicio curso,
                                //fin curso, duración curso, estado (conflictos), materia, responsable.

        //$count=0;
        //comparacion
        // cada registro de marcación válido

        /* generación de registros de asistencia*/
        while($dataSet){
            $esProfesor = false;
            $marcacion = array_pop($dataSet); // marcación a analizar

            // buscamos en los detalles del curso, para comparar con la marcación actual
            foreach($cursosData as $curso){
                // buscamos los detalles del curso para el profesor actual
                // no es el profesor que buscamos
                if(strcmp($curso['codigo'], $marcacion['codigo'])!=0){
                    // hemos leído todos los cursos del profesor actual
                    if($esProfesor){
                        break;
                    }/* else {
                        continue;
                    }*/
                }
                // datos del profesor
                else {
                    $esProfesor = true;
                    $fechaMarca = $marcacion['fecha'];  // cuándo marcó

                    // la fecha de marcación debe estar dentro del periodo de validez del curso.
                    if($fechaMarca >= $curso['desde'] && $fechaMarca <= $curso['hasta']){
                        // día de la semana en que marcó
                        $dia = date ('N', strtotime($fechaMarca));
                        //$debeMarcar = false;
                        list($year, $month, $date) = explode("-", $fechaMarca);
                        $fechaMarca = $date."/".$month."/".$year;

                        // buscamos en los detalles del curso el día que se corresponda con la marcación actual.
                        if($dia == $curso['dia']){
                            // tolerancia, verificamos antes que la marcación se ajuste a la tolerancia de 10 minutos.
                            $inicioTolerable = date("H:i:s", strtotime("+10 minutes", strtotime($curso['inicio'])));
                            $finTolerable = date("H:i:s", strtotime("-10 minutes", strtotime($curso['fin'])));
                            // marcación dentro de los rangos de tolerancia
                            if($inicioTolerable >= $marcacion['entrada'] && $finTolerable <= $marcacion['salida']){

                                //carga de registro en arreglos: fecha de marcación, inicio curso, fin curso, duración curso, estado (conflictos),
                                //materia, responsable.
                                $reg = array ('fecha'  => $fechaMarca,
                                              'inicio' => $curso['inicio'],
                                              'fin'    => $curso['fin'],
                                              'horas'  => $curso['duracionHoras'],
                                              'horacatedra'  => $curso['duracionHora'],
                                              'horasrequeridas' =>$curso['duracionHoras'],
                                              'estado' => 'N',
                                              'materia'  => $curso['materia'],
                                              'resp'   => $curso['responsable'],
                                              'seccion'=> $curso['seccion']);

                                array_push($registerSet, $reg);
                                unset($reg);

                                //liquidacion es todavia null, nunca se asociara a liquidacion
                                //al generar registros, pero si a la inversa. Se asociara liquidaciones a
                                //registros al generar liquidacion.
                            }

                            //Otros casos en que clase no este comprendida enteramente en marcacion
                            else {
                                $horaEntrada = date("H:i", strtotime("00:00"));
                                $horaSalida  = date("H:i", strtotime("00:00"));
                                $entradaValida = false;
                                $salidaValida  = false;
                                // marca entrada después del inicio de una de sus clases y antes de que finalice: entra tarde.
                                if($marcacion['entrada']>=$curso['inicio'] && $marcacion['entrada']<$curso['fin']){
                                    $horaEntrada = substr($marcacion['entrada'],0,5);
                                    $entradaValida = true;
                                }
                                // marca entrada antes del inicio de una de sus clases y sale después del inicio de la clase: entra temprano.
                                elseif(($marcacion['entrada']<=$curso['inicio'])&&($marcacion['salida']>$curso['inicio'])){
                                    $horaEntrada = $curso['inicio'];
                                    $entradaValida = true;
                                }

                                // sale después de que comience el curso pero antes de que finalice: sale temprano.
                                if($marcacion['salida']>$curso['inicio'] && $marcacion['salida']<=$curso['fin']){
                                    $horaSalida = substr($marcacion['salida'],0,5);
                                    $salidaValida = true;
                                }
                                // termina el curso más tarde, pero entra antes de que finalice el curso: sale tarde.
                                elseif(($marcacion['salida']>=$curso['fin'])&&($marcacion['entrada']<$curso['fin'])){
                                    $horaSalida = $curso['fin'];
                                    $salidaValida = true;
                                }

                                if($entradaValida && $salidaValida){
                                    $horas = round((((strtotime($horaSalida) - strtotime($horaEntrada))/60)/$curso['duracionHora'])*10)/10;
                                    //A veces el resultado de horas es cero porque los profesores terminan de dar una clase y faltan
                                    //a la siguiente, pero entre ese tiempo de marcar salida se cuenta un par de minutos dentro de
                                    //la siguiente clase
                                    if($horas >= 1){
                                        //carga en arreglo
                                        $reg = array ('fecha'  => $fechaMarca,
                                                      'inicio' => $horaEntrada,
                                                      'fin'    => $horaSalida,
                                                      'horas'  => $horas,
                                                      'horacatedra'  => $curso['duracionHora'],
                                                      'horasrequeridas' =>$curso['duracionHoras'],
                                                      'estado' => 'N',
                                                      'materia'  => $curso['materia'],
                                                      'resp'   => $curso['responsable'],
                                                      'seccion'=> $curso['seccion']);

                                        array_push($registerSet, $reg);
                                        unset($reg);
                                    }
                                }
                            }
                        }/* else{
                            continue;
                        }*/
                    } /*else {
                        continue;
                    }*/
                }
            }
        }

        // verificamos los registros, solo aquellos que no coinciden con suspensiones de clase serán tenidos en cuenta.
        $registerSet = $this->filtrarClasesValidas($desde, $hasta, $registerSet, $cursosData);


        /*
         * conflictos
         */
        $registerSet = $this->findConflictos($registerSet);



        //test
        /*foreach($registerSet as $r){
            echo $r['fecha']." ,".$r['inicio']." ,".$r['fin']." ,".$r['horas']." ,";
            echo $r['estado']." ,".$r['materia']." ,".$r['resp']."\n";
        }

        return;*/

        foreach($registerSet as $r){
            $responsable = $this->em->find('Default_Model_Responsable', $r['resp']);
            $materia = $this->em->find('Default_Model_Materia', $r['materia']);
            $registro = new Default_Model_Registro();
            $registro->setFecha($r['fecha']);
            $registro->setHoraInicio($r['inicio']);
            $registro->setHoraFin($r['fin']);
            $registro->setHorasCatedra($r['horas']);
            $registro->setDuracionHora($r['horacatedra']);
            $registro->setHorasRequeridas($r['horasrequeridas']);
            $registro->setManual(false);
            $registro->setEstado($r['estado']);
            $registro->setResponsable($responsable);
            $registro->setMateria($materia);
            $registro->setSeccion($r['seccion']);
            $this->em->persist($registro);
        }

        //Modificar fechas inicio_registro y fin_registro en tabla configuracion
        //para que funcionen adecuadamente generaciones de registro futuras
        $inicio_registro = $this->em->createQueryBuilder()
                                ->select('c.idConfiguracion')
                                ->where("c.nombre='inicio_registro'")
                                ->from('Default_Model_Configuracion', 'c')
                                ->getQuery()
                                ->execute();

        $fin_registro = $this->em->createQueryBuilder()
                             ->select('c.idConfiguracion')
                             ->where("c.nombre='fin_registro'")
                             ->from('Default_Model_Configuracion', 'c')
                             ->getQuery()
                             ->execute();

        /*echo $inicio_registro[0]['idConfiguracion']." , ".$fin_registro[0]['idConfiguracion'];*/

        $inicio_registro = $this->em->find('Default_Model_Configuracion', $inicio_registro[0]['idConfiguracion']);
        $fin_registro = $this->em->find('Default_Model_Configuracion', $fin_registro[0]['idConfiguracion']);

        $inicio_registro->setValor($desde);
        $fin_registro->setValor(date("d/m/Y"));

        $this->em->flush();

        X\Msg::Success('Los registros de asistencia han sido generados exitosamente.');
    }



    /****************************************************
     * REPORTES PARA TARJETAS CON CÓDIGOS NO VÁLIDOS    *
     ****************************************************/

    public function verificarErroneosAction(){
        $desde = "01/01/2013";
        $hasta = "20/03/2013";

        $cond_cursos = array("p.codigoTarjeta = '06431AAXXXXX'","p.codigoTarjeta = '04198AAXXXXX'","p.codigoTarjeta = '04693AAXXXXX'",
            "p.codigoTarjeta = '05116ABXXXXX'","p.codigoTarjeta = '05073ABXXXXX'","p.codigoTarjeta = '04268AAXXXXX'","p.codigoTarjeta = '05151AAXXXXX'",
            "p.codigoTarjeta = 'T0010XXXXXXX'","p.codigoTarjeta = 'T0009XXXXXXX'","p.codigoTarjeta = 'T0007XXXXXXX'","p.codigoTarjeta = 'T0008XXXXXXX'",
            "p.codigoTarjeta = 'T0005XXXXXXX'","p.codigoTarjeta = 'T0006XXXXXXX'","p.codigoTarjeta = 'T0001XXXXXXX'","p.codigoTarjeta = 'T0002XXXXXXX'",
            "p.codigoTarjeta = 'T0003XXXXXXX'","p.codigoTarjeta = 'T0004XXXXXXX'","p.codigoTarjeta = '05281AAXXXXX'");

        $cursosData = $this->getCursosAgrupados($desde, $hasta, $cond_cursos);
        
        $cond_marcaciones = array("h.id_empleado = '05281AAXXXXX'");    // verifica las marcaciones con código erróneo

        $marcaciones = $this->getMarcacionesValidasFecha($desde, $hasta, $cond_marcaciones);
/*
        >select('h.fecha')
            ->addSelect('h.tipo')
            ->addSelect('h.entrada_salida')
            ->addSelect('h.id_empleado')*/
        echo "<table>
            <tr>
                <th>Fecha</th>
                <th>Hora</th>
                <th>Tipo</th>
                <th>Empleado</th>
            </tr>
        ";
        foreach($marcaciones as $marcacion){
            echo '<tr>
                <td>'.$marcacion['fecha'].'</td>
                <td>'.$marcacion['entrada_salida'].'</td>
                <td>'.$marcacion['tipo'].'</td>
                <td>'.$marcacion['empleado'].'</td>
            </tr>';
        }
        echo "</table>";
    }


    /****************************************************
     * CONFLICTOS                                       *
     ****************************************************/
    public function materiaAction(){

        //materias dadas por profesores en simultaneo
        $qb = $this->em->createQueryBuilder();

        $materias = $qb->select    ('distinct(m.idMateria)')
                       ->addSelect ('m.nombre')
                       ->from      ('Default_Model_Registro', 'r')
                       ->join      ('r.materia', 'm')
                       //->join      ('r.curso', 'c')
                       //->join      ('c.carreraMateria', 'cm')
                       //->join      ('cm.carrera', 'ca')
                       //->join      ('cm.materia', 'm')
                       //->where     ("r.estado='C'")
                       ->where     ("r.estado='P'")
                       ->orWhere   ("r.estado='A'")
                       ->orderBy   ('m.nombre', 'asc')
                       ->getQuery  ()
                       ->execute   ();

        $this->view->materias = Zend_Json::encode(Array(
            "success" => true,
            "total" => count($materias),
            "rows" => $materias
        ));
    }

    public function profesorAction(){

        $qb = $this->em->createQueryBuilder();

        //profesores que han dado cursos en simultaneo
        $profesores = $qb->select    ('distinct(p.idProfesor)')
                         ->addSelect ('u.apellido')
                         ->addSelect ('u.nombre')
                         ->from      ('Default_Model_Registro', 'r')
                         ->join      ('r.responsable', 're')
                         ->join      ('re.profesor', 'p')
                         ->join      ('p.usuario', 'u')
                         ->where     ("r.estado='C'")
                         ->orWhere   ("r.estado='A'")
                         ->orderBy   ('u.apellido', 'asc')
                         ->getQuery  ()
                         ->execute   ();

        $this->view->profesores = Zend_Json::encode(Array(
            "success" => true,
            "total" => count($profesores),
            "rows" => $profesores
        ));

    }


    /****************************************************
     * RESOLUCIÓN DE CONFLICTOS                         *
     ****************************************************/

    public function ajaxDeleteConflictosAction(){
        // registro a eliminar
        $borrar_id = $this->_request->getPost('idRegistro');

        $delete = $this->em->find('Default_Model_Registro', $borrar_id);

        // si el registro es conflictivo tanto por materia (estado P) como por profesor
        // (estado C), se verifica si los conflictos por profesor y por materia desaparecen.
        if($delete){
            $this->eliminarConflictosCon($delete,'C');
            $this->eliminarConflictosCon($delete,'P');

            $this->em->remove($delete);
        }else{
            X\Msg::Failure('No se encontró el registro a eliminar.');
            return;
        }

        $this->em->flush();

       X\Msg::Success('Se ha eliminado el registro seleccionado.');
    }

    /* verificaciones varias:
    * 1- El total de horas asignadas a los registros no puede superar al total de horas de la clase.
    * 2- El rango de horas asignados debe estar en el rango en que los profesores asistieron a la clase.
    * 3- Hora de salida debe ser mayor o igual a la de entrada.
    * 4- Que los registros dejen de ser conflictivos.
    */
    private static function sonRegistrosMateriaValidos($registros){
        $horas_clase = $registros[0]['horascatedra'];   // cantidad de horas cátedras de la clase.
        $horas_asignadas = 0;
        $min_entrada = "23:59";             // la menor hora de entrada
        $max_salida = "00:00";              // la mayor hora de salida
        foreach($registros as $registro){
            // un decimal
            $horas_registro = ((strtotime($registro['ajusteFin']) - strtotime($registro['ajusteInicio']))/60)/$registro['minutoshora'];
            $horas_asignadas += $horas_registro;
            if($registro['inicio'] < $min_entrada)
                $min_entrada = $registro['inicio'];
            if($registro['fin'] > $max_salida)
                $max_salida = $registro['fin'];

            // Hora de salida debe ser mayor o igual a la de entrada.
            if($registro['ajusteInicio'] > $registro['ajusteFin']){
                X\Msg::Failure('La hora de entrada debe ser menor o igual a la hora de salida.');
                return false;
            }
        }

        // El total de horas asignadas a los registros no puede superar al total de horas de la clase.
        if($horas_asignadas > $horas_clase){
            X\Msg::Failure('El total de horas sobrepasa a las horas de la clase.');
            return false;
        }

        // El rango de horas asignados debe estar en el rango en que los profesores asistieron a la clase.
        foreach($registros as $registro){
            // si no es un registro a eliminar
            if($registro['ajusteInicio'] != $registro['ajusteFin']){
                if($registro['ajusteInicio'] < $min_entrada){
                    X\Msg::Failure('La hora de entrada no puede ser menor que '.$min_entrada);
                    return false;
                }

                if($registro['ajusteFin'] > $max_salida){
                    X\Msg::Failure('La hora de salida no puede ser mayor que '.$max_salida);
                    return false;
                }
            }

            // Que los registros dejen de ser conflictivos: el registro actual no debe ser conflictivo con los demás.
            foreach($registros as $r){
                if($registro['idRegistro'] != $r['idRegistro'] &&
                    RegistroController::overlapping($r['ajusteInicio'], $r['ajusteFin'], $registro['ajusteInicio'], $registro['ajusteFin'])){
                    X\Msg::Failure('Sigue existiendo conflictos pues las horas asignadas se solapan.');
                    return false;
                }
            }
        }

        return true;
    }

    /* verificaciones varias:
    * 1- Las horas asignadas a cada registro deben estar en el rango de horas de marcación.
    * 3- Hora de salida debe ser mayor o igual a la de entrada.
    * 4- Que los registros dejen de ser conflictivos.
    */
    private static function sonRegistrosProfesorValidos($registros){
        $min_entrada = "23:59";             // la menor hora de entrada
        $max_salida = "00:00";              // la mayor hora de salida
        foreach($registros as $registro){
            if($registro['inicio'] < $min_entrada)
                $min_entrada = $registro['inicio'];
            if($registro['fin'] > $max_salida)
                $max_salida = $registro['fin'];

            // Hora de salida debe ser mayor o igual a la de entrada.
            if($registro['ajusteInicio'] > $registro['ajusteFin']){
                X\Msg::Failure('La hora de entrada debe ser menor o igual a la hora de salida.');
                return false;
            }
        }

        // El rango de horas asignados debe estar en el rango de marcación.
        foreach($registros as $registro){
            // si no es un registro a eliminar
            if($registro['ajusteInicio'] != $registro['ajusteFin']){
                if($registro['ajusteInicio'] < $min_entrada){
                    X\Msg::Failure('La hora de entrada no puede ser menor que '.$min_entrada);
                    return false;
                }

                if($registro['ajusteFin'] > $max_salida){
                    X\Msg::Failure('La hora de salida no puede ser mayor que '.$max_salida);
                    return false;
                }
            }

            // Que los registros dejen de ser conflictivos: el registro actual no debe ser conflictivo con los demás.
            foreach($registros as $r){
                if($registro['idRegistro'] != $r['idRegistro'] &&
                    RegistroController::overlapping($r['ajusteInicio'], $r['ajusteFin'], $registro['ajusteInicio'], $registro['ajusteFin'])){
                    X\Msg::Failure('Sigue existiendo conflictos pues las horas asignadas se solapan.');
                    return false;
                }
            }
        }

        return true;
    }

    /*  conflicto: registro cuyos conflictos serán buscados
        no_incluir: array con ids de registros que no se desean incluir en la lista de los registros conflictivos
        tipos: P (conflicto por profesor), C(conflicto por materia/sección), A (todos los conflictos). */
    private function getConflictos($conflicto, $no_incluir = array(), $tipo ='A'){
        $qb = $this->em->createQueryBuilder();

        // se buscan los registros que tienen conflictos de tipo P con el registro $conflicto
        $conflictos = $qb->select ('r')
            ->from      ('Default_Model_Registro', 'r')
            // misma fecha
            ->where     ("r.fecha='".$conflicto->getFecha()."'")
            // overlapping: horas superpuestas
            ->andWhere  ($qb->expr()->orx(  $qb->expr()->andx("r.ajusteInicio>'".$conflicto->getAjusteInicio()."'",
                                                            "r.ajusteInicio<'".$conflicto->getAjusteFin()."'"),

                                            $qb->expr()->andx("r.ajusteInicio<'".$conflicto->getAjusteInicio()."'",
                                                "r.ajusteFin>'".$conflicto->getAjusteInicio()."'"),

                                            $qb->expr()->andx("r.ajusteFin>'".$conflicto->getAjusteInicio()."'",
                                                "r.ajusteFin<'".$conflicto->getAjusteFin()."'"),

                                            $qb->expr()->andx("r.ajusteInicio<'".$conflicto->getAjusteFin()."'",
                                                "r.ajusteFin>'".$conflicto->getAjusteFin()."'"),

                                            $qb->expr()->andx("r.ajusteInicio='".$conflicto->getAjusteInicio()."'",
                                                "r.ajusteFin='".$conflicto->getAjusteFin()."'")))
            // registros diferentes al actual
            ->andWhere("r.idRegistro<>'".$conflicto->getIdRegistro()."'");

        // que registro no incluir en la busqueda
        if(count($no_incluir)>0){
            foreach($no_incluir as $id){
                $conflictos = $conflictos
                    ->andWhere("r.idRegistro<>'".$id."'");
            }
        }

        // que tipo de conflicto buscamos
        switch($tipo){
            // mismo profesor
            case 'P':
                $conflictos = $conflictos
                    ->andWhere ("r.responsable='".$conflicto->getResponsable()->getIdResponsable()."'");
                break;
            // misma materia y sección
            case 'C':
                $conflictos = $conflictos
                    ->andWhere ("r.materia='".$conflicto->getMateria()->getIdMateria()."'")
                    ->andWhere ("r.seccion='".$conflicto->getSeccion()."'");
                break;
        }

        $conflictos = $conflictos
                        ->getQuery  ()
                        ->execute   ();

        return $conflictos;
    }

    /*  antes de eliminar un registro con conflictos, se verifica sus conflictos del tipo especificado,
        puede que desaparezcan. Tipos posibles: P (conflicto por profesor), C (conflicto por materia)    */
    private function eliminarConflictosCon($conflictivo, $tipo ='P' ){
        $quitar_tipo = $tipo == 'P' ? 'C' : 'P';

        $conflictos_por_tipo = $this->getConflictos($conflictivo,array(),$tipo);
        if(count($conflictos_por_tipo) > 0){
            // verificamos cada uno de los conflictos: si no tienen otros conflictos con un registro
            // diferente a $conflictivo, se elimina el conflicto.
            foreach($conflictos_por_tipo as $conflicto){
                // no se realiza la comparación con el registro que se desea eliminar.
                // si no hay registros conflictivos de tipo P: desaparece el conflicto para el profesor ese dia/horario,
                // si no hay registros conflictivos de tipo C: desaparece el conflicto para la materia/sección ese dia/horario
                if(count($this->getConflictos($conflicto, array($conflictivo->getIdRegistro()),$tipo)) <= 0){
                    $estado_actual = $conflicto->getEstado();
                    if($estado_actual == 'A'){
                        $conflicto->setEstado($tipo); // si el registro tenia un conflicto por materia (o por profesor), se mantiene
                    }else{
                        if($estado_actual == $quitar_tipo)
                            $conflicto->setEstado('N');
                    }
                    $this->em->persist($conflicto);
                }
            }
        }
    }

    /*  antes de ajustar las horas inicio y fin de un registro con conflictos, se verifican los registros
        del tipo especificado con que cuenta*/
    private function actualizarConflictosCon($conflictivo,$ajusteInicio,$ajusteFin, $tipo = 'P',$no_incluir = array()){
        $quitar_tipo = $tipo == 'P' ? 'C' : 'P';

        $conflictos_por_tipo = $this->getConflictos($conflictivo,$no_incluir,$tipo);
        $estado_conflictivo = $conflictivo->getEstado();

        if(count($conflictos_por_tipo) > 0){
            // verificamos si con los nuevos ajustes persisten los conflictos
            foreach($conflictos_por_tipo as $conflicto){
                // solo si los nuevos ajustes no se superponen, el conflicto puede desaparecer
                if(!RegistroController::overlapping($conflicto->getAjusteInicio(),$conflicto->getAjusteFin(),$ajusteInicio,$ajusteFin)){
                    // desaparece el conflicto para el registro $conflictivo.
                    if($estado_conflictivo == 'A')
                        $estado_conflictivo = $tipo;
                    else {
                        if($estado_conflictivo == $quitar_tipo)
                            $estado_conflictivo = 'N';
                    }

                    // desaparece el conflicto para el profesor ese dia/horario en caso de que no tenga conflicto con otro registro
                    if(count($this->getConflictos($conflicto, array($conflictivo->getIdRegistro()),$tipo)) <= 0){
                        $estado_actual = $conflicto->getEstado();
                        if($estado_actual == 'A'){
                            $conflicto->setEstado($tipo); // si el registro tenia un conflicto por materia (o por profesor), se mantiene
                        }else {
                            if($estado_actual == $quitar_tipo){
                                $conflicto->setEstado('N');
                            }
                        }
                        $this->em->persist($conflicto);
                    }
                }
            }
        }else{
            // desaparecen los conflictos
            if($estado_conflictivo == 'A')
                $estado_conflictivo = $tipo;
            else{
                if($estado_conflictivo == $quitar_tipo)
                    $estado_conflictivo = 'N';
            }
        }

        return $estado_conflictivo;
    }

    /*  con los nuevos ajustes de horarios, puede que surjan nuevos conflictos con los demás conflictos. En
        ese caso actualizamos el estado de cada uno. */
    private function buscarNuevosConflictosCon($conflictivo, $no_incluir){
        $nuevos_conflictos = $this->getConflictos($conflictivo,$no_incluir);
        $estado_conflictivo = $conflictivo->getEstado();
        if(count($nuevos_conflictos) > 0){
            $responsable = $conflictivo->getResponsable();
            $materia = $conflictivo->getMateria();
            $seccion = $conflictivo->getSeccion();
            foreach($nuevos_conflictos as $conflicto){
                $estado_conflicto = $conflicto->getEstado();
                // conflicto por profesor
                if($responsable==$conflicto->getResponsable()){
                    // nuevo conflicto
                    if(strcmp($estado_conflicto,'N')==0){
                        $conflicto->setEstado('C');
                    }
                    if(strcmp($estado_conflicto,'P')==0){
                        $conflicto->setEstado('A');
                    }
                    // registro verificado
                    if(strcmp($estado_conflictivo,'N')==0){
                        $estado_conflictivo = 'C';
                    }
                    if(strcmp($estado_conflictivo,'P')==0){
                        $estado_conflictivo = 'A';
                    }
                }
                // conflicto por curso
                elseif($materia==$conflicto->getMateria() && $seccion==$conflicto->getSeccion()){
                    if(strcmp($estado_conflicto,'N')==0){
                        $conflicto->setEstado('P');
                    }
                    if(strcmp($estado_conflicto,'C')==0){
                        $conflicto->setEstado('A');
                    }
                    // registro verificado
                    if(strcmp($estado_conflictivo,'N')==0){
                        $estado_conflictivo = 'P';
                    }
                    if(strcmp($estado_conflictivo,'C')==0){
                        $estado_conflictivo = 'A';
                    }
                }

                $this->em->persist($conflicto);
            }
        }

        return $estado_conflictivo;
    }

    public function ajaxResolverConflictosMateriaAction(){
        // procesar registros
        $registros = Zend_Json::decode($this->_request->getPost('registros'));
        $ids = Zend_Json::decode($this->_request->getPost('ids'));

        // validación de los registros
        $success = false;
        if(RegistroController::sonRegistrosMateriaValidos($registros)){
            // si los registros son correctos, se actualizan los datos.
            foreach($registros as $actualizar){

                // registros a eliminar
                if($actualizar['ajusteInicio'] == $actualizar['ajusteFin']){
                    $delete = $this->em->find('Default_Model_Registro', $actualizar['idRegistro']);

                    // si el registro es conflictivo tanto por materia (estado P) como por profesor
                    // (estado C), se verifica si los conflictos por profesor desaparecen.
                    if($delete){
                        $this->eliminarConflictosCon($delete,'P');
                        $this->eliminarConflictosCon($delete,'C');

                        $this->em->remove($delete);
                    }else{
                        X\Msg::Failure('No se encontró el registro a eliminar.');
                        return;
                    }

                }


                // se actualizan datos del registro
                else{
                    // datos registros a actualizar
                    $update = $this->em->find('Default_Model_Registro', $actualizar['idRegistro']);
                    // nuevos datos
                    $ajusteInicio = $actualizar['ajusteInicio'];
                    $ajusteFin = $actualizar['ajusteFin'];
                   // X\Msg::Success('0'.$update->getEstado());

                    // verificamos para cada registro si hay
                    $estado = $this->actualizarConflictosCon($update,$ajusteInicio,$ajusteFin,'C',$ids);
                    $update->setEstado($estado);
                   // X\Msg::Success('1'.$estado);
                    // buscamos los conflictos por profesor con los datos anteriores, verificaremos si dejan de ser conflictivos con la nueva actualización.
                    $estado = $this->actualizarConflictosCon($update,$ajusteInicio,$ajusteFin,'P');
                   // X\Msg::Success('2'.$estado);

                    // ajustes en registro actual
                    $update->setAjusteInicio($ajusteInicio);
                    $update->setAjusteFin($ajusteFin);
                    $update->setHorasCatedra(round((((strtotime($ajusteFin) - strtotime($ajusteInicio))/60)/$actualizar['minutoshora'])*10)/10);
                    $update->setEstado($estado);

                    // además, con los nuevos cambios pueden surgir nuevos conflictos con otros registros, actualizaremos su estado en
                    // caso de que existan. Entre los registros a verificar no se incluirán los que se están procesando actualmente.
                    $estado = $this->buscarNuevosConflictosCon($update, $ids);
                    //X\Msg::Success('3'.$estado);

                    $update->setEstado($estado);
                    $this->em->persist($update);

                }

            }

            try{
                $this->em->flush();
                X\Msg::Success('Los conflictos han sido resueltos con éxito.');
            }catch(Exception $e){
                X\Msg::Failure('Hubo un error en la resolución de conflictos. Error '.$e->getMessage());
            }
        }


    }

    public function ajaxResolverConflictosProfesorAction(){
        // procesar registros
        $registros = Zend_Json::decode($this->_request->getPost('registros'));
        $ids = Zend_Json::decode($this->_request->getPost('ids'));

        // validación de los registros
        $success = false;
        if(RegistroController::sonRegistrosProfesorValidos($registros)){
            // si los registros son correctos, se actualizan los datos.
            foreach($registros as $actualizar){

                // registros a eliminar
                if($actualizar['ajusteInicio'] == $actualizar['ajusteFin']){
                    $delete = $this->em->find('Default_Model_Registro', $actualizar['idRegistro']);

                    // si el registro es conflictivo tanto por materia (estado P) como por profesor
                    // (estado C), se verifica si los conflictos por profesor desaparecen.
                    if($delete){
                        $this->eliminarConflictosCon($delete,'P');
                        $this->eliminarConflictosCon($delete,'C');

                        $this->em->remove($delete);
                    }else{
                        X\Msg::Failure('No se encontró el registro a eliminar.');
                        return;
                    }

                }


                // se actualizan datos del registro
                else{
                    // datos registros a actualizar
                    $update = $this->em->find('Default_Model_Registro', $actualizar['idRegistro']);
                    // nuevos datos
                    $ajusteInicio = $actualizar['ajusteInicio'];
                    $ajusteFin = $actualizar['ajusteFin'];

                    // verificamos para cada registro si hay otros registros con conflictos por profesor, los actualizamos si dejan de ser conflictivos.
                    $estado = $this->actualizarConflictosCon($update,$ajusteInicio,$ajusteFin,'P',$ids);
                    $update->setEstado($estado);
                    // buscamos los conflictos por materia con los datos anteriores, verificaremos si dejan de ser conflictivos con la nueva actualización.
                    $estado = $this->actualizarConflictosCon($update,$ajusteInicio,$ajusteFin,'C');

                    // ajustes en registro actual
                    $update->setAjusteInicio($ajusteInicio);
                    $update->setAjusteFin($ajusteFin);
                    $update->setHorasCatedra(round((((strtotime($ajusteFin) - strtotime($ajusteInicio))/60)/$actualizar['minutoshora'])*10)/10);
                    $update->setEstado($estado);

                    // además, con los nuevos cambios pueden surgir nuevos conflictos con otros registros, actualizaremos su estado en
                    // caso de que existan. Entre los registros a verificar no se incluirán los que se están procesando actualmente.
                    $estado = $this->buscarNuevosConflictosCon($update, $ids);

                    $update->setEstado($estado);
                    $this->em->persist($update);
                }
            }

            try{
                $this->em->flush();
                X\Msg::Success('Los conflictos han sido resueltos con éxito.');
            }catch(Exception $e){
                X\Msg::Failure('Hubo un error en la resolución de conflictos. Error '.$e->getMessage());
            }
        }


    }


    public function ajaxConflictosAction(){

        $tipo = $this->_request->getPost('tipo');

        $registros = array();
        //Traer conflictos de varios profesores, en una materia
        if(strcmp($tipo,'M')==0){

            $idMateria = $this->_request->getPost('idMateria');

            $qb = $this->em->createQueryBuilder();

            $registros = $qb->select    ('r.idRegistro')
                            ->addSelect ('r.fecha')
                            ->addSelect ('r.horaInicio as inicio')
                            ->addSelect ('r.horaFin as fin')
                            ->addSelect ('r.horasCatedra as horas')
                            ->addSelect ('r.seccion as seccion')
                            ->addSelect ('r.ajusteInicio')
                            ->addSelect ('r.ajusteFin')
                            ->addSelect ('r.duracionHora as minutoshora')
                            ->addSelect ('r.horasRequeridas as horascatedra')
                            //->addSelect ('ca.nombre as carrera')
                            //->addSelect ('u.apellido, u.nombre as profesor')
                            ->addSelect ($qb->expr()->concat('u.apellido', $qb->expr()->concat($qb->expr()->literal(', '), 'u.nombre')).'as profesor')
                            ->from      ('Default_Model_Registro', 'r')
                            //->join      ('r.curso', 'c')
                            //->join      ('c.carreraMateria', 'cm')
                            //->join      ('cm.carrera', 'ca')
                            //->join      ('cm.materia', 'm')
                            ->join      ('r.materia', 'm')
                            ->join      ('r.responsable', 're')
                            ->join      ('re.profesor', 'p')
                            ->join      ('p.usuario', 'u')
                            ->where     ("r.estado='P'")
                            ->orWhere   ("r.estado='A'")
                            ->andWhere  ("m.idMateria=".$idMateria)
                            //->orderBy   ('m.nombre', 'asc')
                            ->orderBy   ('r.fecha', 'asc')
                            ->addOrderBy   ('r.horaInicio', 'asc')
                            ->addOrderBy   ('m.nombre', 'asc')
                            //->addOrderBy   ('ca.nombre', 'asc')
                            ->getQuery  ()
                            //->execute   ();
                            ->getArrayResult   ();


            foreach ($registros as &$r) {
                 $r['fecha']  = $r['fecha']->format('d/m/Y');
                 $r['inicio'] = $r['inicio']->format('H:i');
                 $r['fin']    = $r['fin']->format('H:i');
                 $r['ajusteInicio'] = $r['ajusteInicio']->format('H:i');
                 $r['ajusteFin']    = $r['ajusteFin']->format('H:i');
             }

            //var_dump($materias);
            echo Zend_Json::encode(Array(
                "success" => true,
                "total" => count($registros),
                "rows" => $registros
            ));

        }elseif (strcmp($tipo,'P')==0){

            $idProfesor = $this->_request->getPost('idProfesor');

            $qb = $this->em->createQueryBuilder();

            $registros = $qb->select    ('r.idRegistro')
                            ->addSelect ('r.fecha')
                            ->addSelect ('r.horaInicio as inicio')
                            ->addSelect ('r.horaFin as fin')
                            ->addSelect ('r.horasCatedra as horas')
                            ->addSelect ('r.seccion as seccion')
                            ->addSelect ('r.ajusteInicio')
                            ->addSelect ('r.ajusteFin')
                            ->addSelect ('r.duracionHora as minutoshora')
                            //->addSelect ('ca.nombre as carrera')
                            //->addSelect ('u.apellido, u.nombre as profesor')
                            ->addSelect ('m.nombre as materia')
                            ->from      ('Default_Model_Registro', 'r')
                            //->join      ('r.curso', 'c')
                            //->join      ('c.carreraMateria', 'cm')
                            //->join      ('cm.carrera', 'ca')
                            //->join      ('cm.materia', 'm')
                            ->join      ('r.materia', 'm')
                            ->join      ('r.responsable', 're')
                            ->join      ('re.profesor', 'p')
                            ->join      ('p.usuario', 'u')
                            ->where     ("r.estado='C'")
                            ->orWhere   ("r.estado='A'")
                            ->andWhere  ("p.idProfesor=".$idProfesor)
                            //->orderBy   ('m.nombre', 'asc')
                            ->orderBy   ('r.fecha', 'asc')
                            ->addOrderBy   ('r.horaInicio', 'asc')
                            //->addOrderBy   ('u.apellido', 'asc')
                            //->addOrderBy   ('ca.nombre', 'asc')
                            ->getQuery  ()
                            //->execute   ();
                            ->getArrayResult   ();

            foreach ($registros as &$r) {
                 $r['fecha']  = $r['fecha']->format('d/m/Y');
                 $r['inicio'] = $r['inicio']->format('H:i');
                 $r['fin']    = $r['fin']->format('H:i');
                $r['ajusteInicio'] = $r['ajusteInicio']->format('H:i');
                $r['ajusteFin']    = $r['ajusteFin']->format('H:i');
             }

            //var_dump($materias);
            echo Zend_Json::encode(Array(
                "success" => true,
                "total" => count($registros),
                "rows" => $registros
            ));

        }
        $this->view->registros = $registros;

    }


}

